package net.lab1024.sa.admin.module.business.flow.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.module.business.flow.domain.form.FlwDeployQueryForm;
import net.lab1024.sa.admin.module.business.flow.domain.vo.FlwDeployProDefVO;
import net.lab1024.sa.admin.module.business.flow.domain.vo.FlwDeployVO;
import net.lab1024.sa.admin.module.business.flow.service.FlowServiceFactory;
import net.lab1024.sa.admin.module.business.flow.service.FlwDeployService;
import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO;
import net.lab1024.sa.admin.module.system.employee.service.EmployeeService;
import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO;
import net.lab1024.sa.admin.module.system.role.service.RoleService;
import net.lab1024.sa.base.common.domain.PageResult;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.util.SmartPageUtil;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FlwDeployServiceImpl extends FlowServiceFactory implements FlwDeployService {

    @Resource
    private RoleService roleService;

    @Resource
    private EmployeeService employeeService;

    /**
     * 分页查询
     * @param queryForm
     * @return
     */
    @Override
    public PageResult<FlwDeployVO> queryPage(FlwDeployQueryForm queryForm) {
        Page<?> page = SmartPageUtil.convert2PageQuery(queryForm);
        // 1、正确调用 repositoryService 获取部署列表
        // 使用 (int) ((page.getCurrent() - 1) * page瓩.getSize()) 计算 offset
        List<Deployment> deployments = repositoryService.createDeploymentQuery()
                .listPage((int) ((page.getCurrent() - 1) * page.getSize()), (int) page.getSize());

        // 2、将 Deployment 转换为 FlwDeployVO
        List<FlwDeployVO> list = deployments.stream()
                .map(deployment -> convertToVo(deployment))
                .collect(Collectors.toList());

        return SmartPageUtil.convert2PageResult(page, list);
    }

    @Override
    public PageResult<FlwDeployProDefVO> listProcDef(FlwDeployQueryForm queryForm) {
        Page<?> page = SmartPageUtil.convert2PageQuery(queryForm);
        List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery().listPage(
                (int) ((page.getCurrent() - 1) * page.getSize()), (int) page.getSize());
        List<FlwDeployProDefVO> list = definitionList.stream()
                .map(processDefinition -> convertToVo(processDefinition))
                .collect(Collectors.toList());
        return SmartPageUtil.convert2PageResult(page, list);
    }



    private FlwDeployVO convertToVo(Deployment deployment) {
        FlwDeployVO vo = new FlwDeployVO();
        // 设置Deployment相关属性
        vo.setId(deployment.getId());
        vo.setKey(deployment.getKey());
        vo.setName(deployment.getName());
        vo.setName(deployment.getName());
        vo.setDeployTime(deployment.getDeploymentTime());
        return vo;
    }

    private FlwDeployProDefVO convertToVo(ProcessDefinition processDefinition) {
        FlwDeployProDefVO flwDeployProDefVO = new FlwDeployProDefVO();
        // 设置Deployment相关属性
        flwDeployProDefVO.setId(processDefinition.getId());
        flwDeployProDefVO.setName(processDefinition.getName());
        flwDeployProDefVO.setCategory(processDefinition.getCategory());
        flwDeployProDefVO.setDeploymentId(processDefinition.getDeploymentId());
        flwDeployProDefVO.setDeploymentName(processDefinition.getName());
        flwDeployProDefVO.setDescroption(processDefinition.getDescription());
        flwDeployProDefVO.setTenantId(processDefinition.getTenantId());
        flwDeployProDefVO.setFlowKey(processDefinition.getKey());
        flwDeployProDefVO.setSuupensionState(processDefinition.isSuspended());
        flwDeployProDefVO.setVersion(processDefinition.getVersion());
        return flwDeployProDefVO;
    }
    /**
     * 根据id查询流程图
     */
    @Override
    public byte [] getProcessDiagram(String id) {
        // 1、根据流程部署id查询出流程部署的信息
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(id).singleResult();
        try{
            InputStream in = repositoryService
                    .getResourceAsStream(definition.getDeploymentId()
                            , definition.getDiagramResourceName());
            byte[] b = new byte[in.available()];
            in.read(b);
            return b;
        }catch (IOException e){
            System.out.println("读取的流程图文件不存在!!!");
        }
        return new byte[0];
    }

    /**
     * 根据id查询流程xml
     */
    @Override
    public String queryFlowXml(String id) {
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(id).singleResult();
        // 添加空值检查
        if (definition == null) {
            System.err.println("未找到ID为 " + id + " 的流程定义");
        }

        try {
            InputStream in = repositoryService
                    .getResourceAsStream(definition.getDeploymentId(), definition.getResourceName());

            // 使用Java原生方法读取输入流
            StringBuilder sb = new StringBuilder();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line).append("\n");
                }
            }
            return sb.toString();

        } catch (Exception e) {
            System.out.println("读取的流程文件不存在!!!");
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<Map<String, Object>> getFlowDef(String deploymentId) {
        // 临时存储：key=任务名称，value=该任务下的属性Map（key=type，value=值集合）
        Map<String, Map<String, List<String>>> taskAttrTempMap = new HashMap<>();

        // 1. 查询流程定义
        List<ProcessDefinition> processDefList = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploymentId)
                .list();

        if (processDefList.isEmpty()) {
            log.error("部署ID: {} 未找到关联的流程定义", deploymentId);
            return new ArrayList<>();
        }

        // 2. 遍历流程定义，提取UserTask属性
        for (ProcessDefinition processDef : processDefList) {
            log.info("当前流程定义ID: {}, 流程Key: {}", processDef.getId(), processDef.getKey());

            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDef.getId());
            Process mainProcess = bpmnModel.getMainProcess();
            if (mainProcess == null) {
                log.error("流程定义ID: {} 未找到主流程", processDef.getId());
                continue;
            }

            List<FlowElement> flowElementList = new ArrayList<>(mainProcess.getFlowElements());
            for (FlowElement flowElement : flowElementList) {
                if (flowElement instanceof UserTask) {
                    UserTask userTask = (UserTask) flowElement;
                    String taskName = flowElement.getName();
                    if (taskName == null || taskName.isEmpty()) {
                        log.warn("UserTask(ID:{})未配置任务名称，跳过", userTask.getId());
                        continue;
                    }

                    // 初始化任务属性Map
                    taskAttrTempMap.computeIfAbsent(taskName, k -> new HashMap<>());
                    Map<String, List<String>> attrMap = taskAttrTempMap.get(taskName);

                    // 处理assignee（负责人）：提取真实标识到key字段
                    String assignee = userTask.getAssignee();
                    if (assignee != null && !assignee.isEmpty()) {
                        attrMap.computeIfAbsent("assignee", k -> new ArrayList<>()).add(assignee);
                    }

                    // 处理candidateUsers（候选用户）：提取真实标识到key字段
                    List<String> candidateUsers = userTask.getCandidateUsers();
                    if (!candidateUsers.isEmpty()) {
                        attrMap.computeIfAbsent("candidateUsers", k -> new ArrayList<>()).addAll(candidateUsers);
                    }

                    // 处理candidateGroups（候选组）：提取真实标识到key字段
                    List<String> candidateGroups = userTask.getCandidateGroups();
                    if (!candidateGroups.isEmpty()) {
                        attrMap.computeIfAbsent("candidateGroups", k -> new ArrayList<>()).addAll(candidateGroups);
                    }
                }
            }
        }

        // 3. 转换为目标格式：添加key字段，value置空
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Map.Entry<String, Map<String, List<String>>> taskEntry : taskAttrTempMap.entrySet()) {
            String taskName = taskEntry.getKey();
            Map<String, List<String>> attrMap = taskEntry.getValue();

            for (Map.Entry<String, List<String>> attrEntry : attrMap.entrySet()) {
                String type = attrEntry.getKey();
                List<String> originalValues = attrEntry.getValue();

                // 提取原始值中的真实标识作为key（使用findFlowDefUserOrGroup方法）
                String key = originalValues.stream()
                        .map(this::findFlowDefUserOrGroup)
                        .collect(Collectors.joining(","));

                Map<String, Object> resultMap = new HashMap<>();
                resultMap.put("name", taskName);       // 任务名称（如“人事审批”）
                resultMap.put("type", type);           // 类型（如“candidateUsers”）
                resultMap.put("value", "");            // value置空
                resultMap.put("key", key);             // key为提取后的真实标识（如“user20,user3”）

                resultList.add(resultMap);
            }
        }

        // 4. 附加角色和用户列表
        ResponseDTO<List<RoleVO>> allRole = roleService.getAllRole();
        List<RoleVO> allRoleData = allRole.getData();
        if (!allRoleData.isEmpty()) {
            Map<String, Object> rolesMap = new HashMap<>();
            rolesMap.put("role", allRoleData);
            resultList.add(rolesMap);
        }

        ResponseDTO<List<EmployeeVO>> allEmployee = employeeService.queryAllEmployee(false);
        List<EmployeeVO> allEmployeeData = allEmployee.getData();
        if (!allEmployeeData.isEmpty()) {
            Map<String, Object> employeesMap = new HashMap<>();
            employeesMap.put("user", allEmployeeData);
            resultList.add(employeesMap);
        }

        return resultList;
    }

    // 工具方法：提取${}中的真实标识
    public String findFlowDefUserOrGroup(String str) {
        Pattern pattern = Pattern.compile("\\$\\{([^}]+)}");
        Matcher matcher = pattern.matcher(str);
        List<String> list = new ArrayList<>();
        while (matcher.find()) {
            String realValue = matcher.group(1); // 提取${}内的内容（如“user20”“user3”）
            list.add(realValue);
        }
        if (list.size() == 1) {
            return list.get(0);
        }
        return String.join(",", list); // 多值拼接（如“user20,user3”）
    }

    public List<Map<String,Object>> getFlowDef1(String id) {
        log.info(" FlwDeployServiceImpl.getFlowDef.id:{}",id);
        // 1、根基流程部署id获取BpmnModel对象
        BpmnModel bpmnModel = repositoryService.getBpmnModel(id);
        List<Map<String,Object>> list = new ArrayList<>();
        // 2、从BpmnModel对象中的process属性 获取相关的 userTask 信息
        Process mainProcess = bpmnModel.getMainProcess();
        log.info(" FlwDeployServiceImpl.getFlowDef.mainProcess:{}",mainProcess.getDataObjects());
        // 3、从Process获取所有的流程元素
        Collection<FlowElement> flowElements = mainProcess.getFlowElements();
        // 3、1 遍历 flowElements 集合
        for (FlowElement flowElement : flowElements) {
            if (flowElement instanceof UserTask){
                UserTask userTask = (UserTask) flowElement;
                Map<String, List<ExtensionAttribute>> attributes = userTask.getAttributes();
                Set<String> keySet = attributes.keySet();
                for (String key : keySet) {
                    // 3、2 这里的key有三种类型 assignee, candidateUsers, candidateGroups
                    List<ExtensionAttribute> extensionAttributes = attributes.get(key);
                    if (extensionAttributes != null){
                        for (ExtensionAttribute extensionAttribute : extensionAttributes){
                            String value = extensionAttribute.getValue();
                            HashMap<String, Object> map = new HashMap<>();
                            map.put("name",flowElement.getName());
                            map.put("type",key);
                            //  ${user1} ${user2} ${group}
                            map.put("value","");
                            map.put("key",findFlowDefUserOrGroup(value));
                            list.add(map);
                        }
                    }
                }
            }
        }
        return list ;
    }
}
